package com.plat.net.http.context;

import com.plat.net.http.annotation.RequestMapping;
import com.plat.net.http.annotation.RestController;
import com.plat.net.http.config.Config;
import com.plat.net.http.ioc.annotation.annotation.Component;
import com.plat.net.http.vo.HandleMappingVo;

import java.io.File;
import java.io.FileFilter;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class ControllerContext {

    //保存类路径的缓存
    private List<String> classCache = Collections.synchronizedList(new ArrayList<String>());
    //保存类实例的容器
    private Map<String, Object> beanFactory = new ConcurrentHashMap<>();
    //Controller方法与请求路径的映射关系
    private Map<String, HandleMappingVo> handleMapping = new ConcurrentHashMap<>();

    //单例
    private static ControllerContext instance = new ControllerContext();

    public static ControllerContext getInstance() {
        return instance;
    }

    //初始化
    private ControllerContext() {
        String path = Config.CONTROLLER_PATH;
        //扫描包
        scanPackage(path);
        //注册Bean
        registerBean();
        //MVC路径映射
        mappingMVC();
    }

    /**
     * 扫描包
     */
    private void scanPackage(final String path) {
        URL url = this.getClass().getClassLoader().getResource(path.replaceAll("\\.", "/"));
        try {
            File file = new File(url.toURI());
            file.listFiles(new FileFilter() {
                //遍历当前目录下的所有文件
                @Override
                public boolean accept(File childFile) {
                    //递归查找文件
                    if (childFile.isDirectory()) {
                        scanPackage(path + "." + childFile.getName());
                    } else {
                        if (childFile.getName().endsWith(".class")) {
                            String classPath = path + "." + childFile.getName().replace(".class", "");
                            classCache.add(classPath);
                        }
                    }
                    return true;
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 注册Bean
     */
    private void registerBean() {
        if (classCache.isEmpty()) {
            return;
        }
        for (String path : classCache) {
            try {
                //使用反射，通过类路径获取class 对象
                Class<?> clazz = Class.forName(path);
                //找出需要被容器管理的类，@RestController
                if (clazz.isAnnotationPresent(RestController.class)) {
                    //根据类对象，创建实例
                    Object instance = clazz.newInstance();
                    //首字母小写的类名作为默认名字
                    String aliasName = lowerClass(clazz.getSimpleName());
                    if (clazz.isAnnotationPresent(RestController.class)) {
                        RestController controller = clazz.getAnnotation(RestController.class);
                        if (!"".equals(controller.value())) {
                            aliasName = controller.value();
                        }
                    }
                    if (beanFactory.get(aliasName) == null) {
                        beanFactory.put(aliasName, instance);
                    }
                }
                if (clazz.isAnnotationPresent(Component.class)) {

                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /*
     * MVC路径映射
     */
    private void mappingMVC() {
        //遍历容器，保存Requestmapping、Contoller与请求路径的对应关系
        for (Map.Entry<String, Object> entry : beanFactory.entrySet()) {
            Object instance = entry.getValue();
            Class<?> clazz = instance.getClass();
            if (clazz.isAnnotationPresent(RestController.class)) {
                //获取类上的路径
                String classPath = "";
                if (clazz.isAnnotationPresent(RequestMapping.class)) {
                    RequestMapping clazzAnnotation = clazz.getAnnotation(RequestMapping.class);
                    classPath = clazzAnnotation.value();
                }
                //获取方法上的路径
                Method[] methods = clazz.getMethods();
                for (Method method : methods) {
                    if (method.isAnnotationPresent(RequestMapping.class)) {
                        RequestMapping methodAnnotation = method.getAnnotation(RequestMapping.class);
                        if (methodAnnotation != null) {
                            String methodPath = methodAnnotation.value();
                            String requestPath = classPath + methodPath;
                            HandleMappingVo mappingVo = new HandleMappingVo(instance, method, requestPath);
                            handleMapping.put(requestPath, mappingVo);
                        }
                    }
                }
            }
        }
    }

    /**
     * 首字母小写
     */
    private String lowerClass(String simpleName) {
        char[] chars = simpleName.toCharArray();
        chars[0] += 32;
        String result = String.valueOf(chars);
        return result;
    }

    /**
     * 获取Controller方法与请求路径的映射关系
     */
    public HandleMappingVo getHandleMapping(String requestPath) {
        return handleMapping.get(requestPath);
    }
}